////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2001.
// -------------------------------------------------------------------------
//  File name:   EditorUtils.cpp
//  Version:     v1.00
//  Created:     30/11/2001 by Timur.
//  Compilers:   Visual C++ 6.0
//  Description: 
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "EditorUtils.h"
#include <malloc.h>

//////////////////////////////////////////////////////////////////////////
void HeapCheck::Check( const char *file,int line )
{
	#ifdef _DEBUG

	_ASSERTE(_CrtCheckMemory());

	/*
   int heapstatus = _heapchk();
   switch( heapstatus )
   {
   case _HEAPOK:
      break;
   case _HEAPEMPTY:
      break;
   case _HEAPBADBEGIN:
			{
				CString str;
				str.Format( "Bad Start of Heap, at file %s line:%d",file,line );
				MessageBox( NULL,str,"Heap Check",MB_OK );
			}
      break;
   case _HEAPBADNODE:
			{
				CString str;
				str.Format( "Bad Node in Heap, at file %s line:%d",file,line );
				MessageBox( NULL,str,"Heap Check",MB_OK );
			}
      break;
   }
	 */
	#endif
}

namespace EditorMemoryUtils
{
	void operator delete[](void *pUserData)
	{
#ifdef _DEBUG
		//_CrtMemBlockHeader * pHead;

		// Removed it. I am assuming we don't care about these hooks for runtime checks.
		//RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));

		if (pUserData == NULL)
			return;

		//_mlock(_HEAP_LOCK);  /* block other threads */
		//__TRY

		//	/* get a pointer to memory block header */
		//	pHead = pHdr(pUserData);

		///* verify block type */
		//_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));

		_free_dbg(pUserData, _NORMAL_BLOCK);

		//__FINALLY
		//	_munlock(_HEAP_LOCK);  /* release other threads */
		//__END_TRY_FINALLY
#else
		// Removed it. I am assuming we don't care about these hooks for runtime checks.
		//RTCCALLBACK(_RTC_Free_hook, (p, 0));
		CryModuleCRTFree(pUserData);
#endif //_DEBUG
	}
}

//////////////////////////////////////////////////////////////////////////
BOOL CMFCUtils::LoadTrueColorImageList( CImageList &imageList,UINT nIDResource,int nIconWidth,COLORREF colMaskColor )
{
	CBitmap bitmap;
	BITMAP bmBitmap;
	if (!bitmap.Attach(LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(nIDResource),IMAGE_BITMAP, 0, 0,LR_DEFAULTSIZE|LR_CREATEDIBSECTION)))
		return FALSE;
	if (!bitmap.GetBitmap(&bmBitmap))
		return FALSE;
	CSize		cSize(bmBitmap.bmWidth, bmBitmap.bmHeight); 
	RGBTRIPLE*	rgb		= (RGBTRIPLE*)(bmBitmap.bmBits);
	int	nCount	= cSize.cx/nIconWidth;
	if (!imageList)
	{
		if (!imageList.Create(nIconWidth, cSize.cy, ILC_COLOR32/*ILC_COLOR24*/|ILC_MASK, nCount, 0))
			return FALSE;
	}

	if (imageList.Add(&bitmap,colMaskColor) == -1)
		return FALSE;
	return TRUE;
}

//////////////////////////////////////////////////////////////////////////
void CMFCUtils::TransparentBlt( HDC hdcDest, int nXDest, int nYDest, int nWidth,int nHeight, HBITMAP hBitmap, int nXSrc, int nYSrc,
																COLORREF colorTransparent )
{
	CDC dc, memDC, maskDC, tempDC;
	dc.Attach( hdcDest );
	maskDC.CreateCompatibleDC(&dc);
	CBitmap maskBitmap;

	//add these to store return of SelectObject() calls
	CBitmap* pOldMemBmp = NULL;
	CBitmap* pOldMaskBmp = NULL;
	HBITMAP hOldTempBmp = NULL;

	memDC.CreateCompatibleDC(&dc);
	tempDC.CreateCompatibleDC(&dc);
	CBitmap bmpImage;
	bmpImage.CreateCompatibleBitmap( &dc, nWidth, nHeight );
	pOldMemBmp = memDC.SelectObject( &bmpImage );

	hOldTempBmp = (HBITMAP) ::SelectObject( tempDC.m_hDC, hBitmap );

	memDC.BitBlt( 0,0,nWidth, nHeight, &tempDC, nXSrc, nYSrc, SRCCOPY );

	// Create monochrome bitmap for the mask
	maskBitmap.CreateBitmap( nWidth, nHeight, 1, 1, NULL );
	pOldMaskBmp = maskDC.SelectObject( &maskBitmap );
	memDC.SetBkColor( colorTransparent );

	// Create the mask from the memory DC
	maskDC.BitBlt( 0, 0, nWidth, nHeight, &memDC,
		0, 0, SRCCOPY );

	// Set the background in memDC to black. Using SRCPAINT with black 
	// and any other color results in the other color, thus making 
	// black the transparent color
	memDC.SetBkColor(RGB(0,0,0));
	memDC.SetTextColor(RGB(255,255,255));
	memDC.BitBlt(0, 0, nWidth, nHeight, &maskDC, 0, 0, SRCAND);

	// Set the foreground to black. See comment above.
	dc.SetBkColor(RGB(255,255,255));
	dc.SetTextColor(RGB(0,0,0));
	dc.BitBlt(nXDest, nYDest, nWidth, nHeight, &maskDC, 0, 0, SRCAND);

	// Combine the foreground with the background
	dc.BitBlt(nXDest, nYDest, nWidth, nHeight, &memDC,
		0, 0, SRCPAINT);


	if (hOldTempBmp)
		::SelectObject( tempDC.m_hDC, hOldTempBmp);
	if (pOldMaskBmp)
		maskDC.SelectObject( pOldMaskBmp );
	if (pOldMemBmp)
		memDC.SelectObject( pOldMemBmp );

	dc.Detach();
}

//////////////////////////////////////////////////////////////////////////
void CMFCUtils::LoadShortcuts(CXTPCommandBars *pCommandBars, UINT nMenuIDResource, const char *pSectionNameForLoading)
{
	CString shortcutsSection = "Shortcuts";
	shortcutsSection += "\\";
	shortcutsSection += pSectionNameForLoading;
	pCommandBars->GetShortcutManager()->SetAccelerators(nMenuIDResource);
	pCommandBars->GetShortcutManager()->LoadShortcuts(shortcutsSection);
}

//////////////////////////////////////////////////////////////////////////
void CMFCUtils::ShowShortcutsCustomizeDlg(CXTPCommandBars *pCommandBars, UINT nMenuIDResource, const char *pSectionNameForSaving)
{
	if(pCommandBars != NULL)
	{
		CXTPCustomizeSheet dlg(pCommandBars);

		// Remove unnecessary pages.
		for(int i=0; i<dlg.GetPageCount(); ++i)
			dlg.RemovePage(i);
		dlg.RemovePage(dlg.GetCommandsPage());

		CXTPCustomizeKeyboardPage pageKeyboard(&dlg);
		dlg.AddPage(&pageKeyboard);
		pageKeyboard.AddCategories(nMenuIDResource, TRUE);
		dlg.SetActivePage(&pageKeyboard);

		dlg.DoModal();

		CString shortcutsSection = "Shortcuts";
		shortcutsSection += "\\";
		shortcutsSection += pSectionNameForSaving;
		pCommandBars->GetShortcutManager()->SaveShortcuts(shortcutsSection);
	}
}

//////////////////////////////////////////////////////////////////////////
void CMFCUtils::ExportShortcuts(CXTPShortcutManager *pShortcutMgr)
{
	char szFilters[] = "HOT Files (*.hot)|*.hot||";
	CAutoDirectoryRestoreFileDialog dlg(FALSE, "hot", "shortcuts.hot", OFN_OVERWRITEPROMPT|OFN_NOCHANGEDIR, szFilters);

	if (dlg.DoModal() == IDOK) 
	{
		CStdioFile cFile;
		if(cFile.Open(dlg.GetPathName(), CFile::modeCreate | CFile::modeWrite | CFile::typeText) == FALSE)
		{
			CString errMsg;
			errMsg.Format("Writing to the file, %s failed!", dlg.GetPathName());
			AfxMessageBox(errMsg);
			return;
		}

		CArchive archive(&cFile, CArchive::store);
		pShortcutMgr->SerializeShortcuts(archive);
		archive.Close();
		cFile.Close();
	}
}

//////////////////////////////////////////////////////////////////////////
void CMFCUtils::ImportShortcuts(CXTPShortcutManager *pShortcutMgr, const char *pSectionNameForSaving)
{
	char szFilters[] = "HOT Files (*.hot)|*.hot||";
	CAutoDirectoryRestoreFileDialog dlg(TRUE, "hot", "*.hot", OFN_FILEMUSTEXIST|OFN_NOCHANGEDIR, szFilters);

	if (dlg.DoModal() == IDOK) 
	{
		CStdioFile cFile;
		if(cFile.Open(dlg.GetPathName(), CFile::modeRead | CFile::typeText) == FALSE)
		{
			CString errMsg;
			errMsg.Format("Reading the file, %s failed!", dlg.GetPathName());
			AfxMessageBox(errMsg);
			return;
		}

		CArchive archive(&cFile, CArchive::load);
		pShortcutMgr->SerializeShortcuts(archive);
		archive.Close();
		cFile.Close();

		if (pSectionNameForSaving)
		{
			CString shortcutsSection = "Shortcuts";
			shortcutsSection += "\\";
			shortcutsSection += pSectionNameForSaving;
			pShortcutMgr->SaveShortcuts(shortcutsSection);
		}
	}
}